<template>
  <template v-if="searchBoxItem.type === 'input'">
    <el-input
      class="search-bar-item header-input"
      v-model="componentSearchForm[searchBoxItem.field]"
      type="text"
      :placeholder="searchBoxItem.placeholder || `${searchBoxItem.name}`"
      @input="handleInputChange"
      :clearable="searchBoxItem.allowClear === false ? false : true"
      :maxlength="100"
      :style="searchBoxItem.style"
      :suffix-icon="h(GIcon, { type: 'c-xian-sousuo', style: 'font-size: 14px' })"
    >
    </el-input>
  </template>
  <template v-else-if="searchBoxItem.type === 'radio'">
    <el-radio-group
      class="header-radio"
      @change="handleSelectChange"
      v-model="componentSearchForm[searchBoxItem?.field]"
    >
      <el-radio-button
        v-for="(item, index) in getOptions(searchBoxItem)"
        :key="index"
        :label="searchBoxItem.valueField ? item[searchBoxItem.valueField] : item.value"
      >
        {{ item.label }}</el-radio-button
      >
    </el-radio-group>
  </template>
  <template v-else-if="searchBoxItem.type === 'select'">
    <CSelect
      size="default"
      class="search-bar-item header-select"
      v-model="componentSearchForm[searchBoxItem.field]"
      :placeholder="searchBoxItem.placeholder || `${searchBoxItem.name}`"
      :filterable="searchBoxItem.filterable || false"
      v-bind="handleBind(searchBoxItem)"
      @change="handleSelectChange"
      :clearable="searchBoxItem.allowClear === false ? false : true"
      :prop-options="getOptions(searchBoxItem)"
      @visible-change="handleVisibleChange($event, searchBoxItem)"
      :style="searchBoxItem.style"
      :disabled="searchBoxItem?.disabled ?? false"
    >
      <template #suffix v-if="Object.keys(handleBind(searchBoxItem)).includes('remote')">
        <CIcon
          class="header-select--remote-icon"
          type="c-xian-sousuo"
          style="style: font-size: 14px"
        ></CIcon>
      </template>
      <el-option
        v-for="(item, index) in getOptions(searchBoxItem)"
        :key="index"
        :value="searchBoxItem.valueField ? item[searchBoxItem.valueField] : item.value"
        :label="item.label"
      >
        <div class="g-flex-between-center">
          <span :class="{ 'g-mr10': searchBoxItem.selectSubTitle }">{{ item.label }}</span>
          <span class="g-font-12n4" v-if="searchBoxItem.selectSubTitle">{{
            item[searchBoxItem.selectSubTitle]
          }}</span>
        </div>
      </el-option>
    </CSelect>
  </template>
  <template v-else-if="searchBoxItem.type === 'cascader'">
    <el-cascader
      class="search-bar-item header-select"
      :filterable="searchBoxItem.filterable || false"
      v-model="componentSearchForm[searchBoxItem.field]"
      :placeholder="searchBoxItem.placeholder || `${searchBoxItem.name}`"
      v-bind="handleBind(searchBoxItem)"
      :props="cascaderProps"
      @change="handleSelectChange"
      :clearable="searchBoxItem.allowClear === false ? false : true"
      :options="getOptions(searchBoxItem)"
      :style="searchBoxItem.style"
    >
    </el-cascader>
  </template>
  <template v-else-if="searchBoxItem.type === 'datePicker'">
    <el-date-picker
      size="default"
      class="search-bar-item header-select"
      :type="searchBoxItem.dateType"
      v-model="componentSearchForm[searchBoxItem.field]"
      @change="handleInputChange"
      range-separator="-"
      :start-placeholder="searchBoxItem.startPlaceholder || `${searchBoxItem.name}开始`"
      :end-placeholder="searchBoxItem.endPlaceholder || `${searchBoxItem.name}截止`"
      :placeholder="searchBoxItem.placeholder || `${searchBoxItem.name}`"
      :value-format="searchBoxItem.format || 'YYYY/MM/DD'"
      :default-time="searchBoxItem.dateType == 'datetimerange' ? defaultTime2 : defaultTime1"
      :style="searchBoxItem.style"
      :unlink-panels="true"
    ></el-date-picker>
  </template>
  <template v-else-if="searchBoxItem.type === 'button'">
    <template v-if="searchBoxItem.name">
      <el-button
        :icon="
          searchBoxItem.buttonIcon && typeof searchBoxItem.buttonIcon !== 'string'
            ? searchBoxItem.buttonIcon
            : undefined
        "
        :type="searchBoxItem.buttonType || 'default'"
        @click="searchBoxItem.buttonMethod"
      >
        <CIcon
          class="g-mr4"
          :type="searchBoxItem.buttonIcon"
          v-if="searchBoxItem.buttonIcon && typeof searchBoxItem.buttonIcon === 'string'"
        ></CIcon>
        {{ searchBoxItem.name }}</el-button
      >
    </template>
    <template v-else>
      <el-button
        :icon="
          searchBoxItem.buttonIcon && typeof searchBoxItem.buttonIcon !== 'string'
            ? searchBoxItem.buttonIcon
            : undefined
        "
        :type="searchBoxItem.buttonType || 'default'"
        @click="searchBoxItem.buttonMethod"
        :style="searchBoxItem.style"
      >
        <CIcon
          :type="searchBoxItem.buttonIcon"
          v-if="searchBoxItem.buttonIcon && typeof searchBoxItem.buttonIcon === 'string'"
        ></CIcon
      ></el-button>
    </template>
  </template>
  <template v-else-if="searchBoxItem.type === 'custom'">
    <component
      v-model:value="componentSearchForm[searchBoxItem.field]"
      :is="searchBoxItem.customItem"
      v-bind="{ ...searchBoxItem }"
      @change="handleSearchChange"
    ></component>
  </template>
</template>

<script lang="ts" setup name="SearchBarItem">
import { defineProps, defineEmits, reactive, h, ref } from 'vue';
import { CSelect } from '@/components/CSelect/index';
import { GIcon } from '@/components/GIcon/index';
import { debounce } from 'lodash';
import type { SearchOptionsType } from './search-bar';
import { buildUUID } from '@/utils/uuid';
import * as selectOptions from '@/constants/enum';

interface SearchBarItemProps {
  searchBoxItem: SearchOptionsType;
  searchForm: any;
}

const props = defineProps<SearchBarItemProps>();
const cascaderProps = {
  emitPath: false
};
const emits = defineEmits(['change']);

const componentSearchForm = reactive(props.searchForm);

// 处理输入框改变事件
const handleInputChange = debounce(() => {
  handleSearchChange();
}, 600);

// select change
const handleSelectChange = (value: any, option: any) => {
  console.log('handleSelectChange', value, option);
  handleSearchChange();
};

// 处理搜索改变事件
const handleSearchChange = () => {
  emits('change', componentSearchForm);
};

// 异步获取的选项列表
const asyncOptions = ref<any>({});

// 获取选项列表
const getOptions = (searchBoxItem: SearchOptionsType) => {
  console.log('getOptions', searchBoxItem);
  if (searchBoxItem?.options?.length) {
    return searchBoxItem.options;
  } else if (searchBoxItem.loadData && searchBoxItem.uuid) {
    // 需要异步获取的
    return asyncOptions.value[searchBoxItem.uuid];
  } else if (searchBoxItem.fixedOption) {
    return (selectOptions as any)[searchBoxItem.fixedOption] || [];
  } else if (searchBoxItem.remoteMethod && searchBoxItem.uuid) {
    // 需要异步获取的
    return asyncOptions.value[searchBoxItem.uuid];
  }
  console.log('getOptions result end');
  return [];
};

// 远程获取选项数据
function handleRemoteMethod(query: string, searchBoxItem: SearchOptionsType) {
  if (!searchBoxItem.remoteMethod) return;
  const result = searchBoxItem.remoteMethod(query);
  if (
    (typeof result === 'object' || typeof result === 'function') &&
    typeof result.then === 'function'
  ) {
    result.then((res: any) => {
      console.log('handleRemoteMethod res', res);
      asyncOptions.value[searchBoxItem.uuid as string] = res;
    });
  }
}

// 用于搜索select在筛选项出现时重新执行全量搜素，用于再次打开时能选择全部数据
function handleVisibleChange(val: any, searchBoxItem: SearchOptionsType) {
  console.log('val', val, 'searchBoxItem', searchBoxItem);
  if (!searchBoxItem.remoteMethod) return;
  if (val) {
    handleRemoteMethod('', searchBoxItem);
  }
}

// 绑定参数
function handleBind(searchBoxItem: SearchOptionsType) {
  const bindObj = {};

  if (searchBoxItem.remoteMethod) {
    Object.assign(bindObj, {
      remote: true,
      filterable: true,
      'remote-method': (query: string) => handleRemoteMethod(query, searchBoxItem),
      class: 'header-select--remote'
    });
  }

  // 是否自适应宽度
  if (searchBoxItem?.selectOption?.autoWidth) {
    Object.assign(bindObj, {
      autoWidth: searchBoxItem.selectOption.autoWidth
    });
    if (searchBoxItem?.selectOption?.defaultAutoWidth) {
      Object.assign(bindObj, {
        defaultAutoWidth: searchBoxItem.selectOption.defaultAutoWidth
      });
    }

    if (searchBoxItem?.selectOption?.maxAutoWidth) {
      Object.assign(bindObj, {
        maxAutoWidth: searchBoxItem.selectOption.maxAutoWidth
      });
    }
  }

  console.log('handleBind', bindObj, searchBoxItem);

  return bindObj;
}

// 处理异步选项获取
const preformAsyncOptions = (searchBoxItem: SearchOptionsType) => {
  if (searchBoxItem.loadData) {
    searchBoxItem.uuid = buildUUID();
    asyncOptions.value[searchBoxItem.uuid as string] = [];
    const result = (searchBoxItem as any).loadData();
    if (
      (typeof result === 'object' || typeof result === 'function') &&
      typeof result.then === 'function'
    ) {
      result.then((res: any) => {
        console.log('loadData res', res);
        asyncOptions.value[searchBoxItem.uuid as string] = res;
      });
    }
  } else if (searchBoxItem.remoteMethod) {
    searchBoxItem.uuid = buildUUID();
    asyncOptions.value[searchBoxItem.uuid as string] = [];
    const result = (searchBoxItem as any).remoteMethod('');
    if (
      (typeof result === 'object' || typeof result === 'function') &&
      typeof result.then === 'function'
    ) {
      result.then((res: any) => {
        console.log('loadData res', res);
        asyncOptions.value[searchBoxItem.uuid as string] = res;
      });
    }
  }
};

// 处理异步选项获取
preformAsyncOptions(props.searchBoxItem);

const defaultTime2 = [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]; // '12:00:00', '08:00:00'
const defaultTime1 = [new Date(2000, 1, 1, 0, 0, 0)]; // '12:00:00', '08:00:00'
</script>

<style lang="scss" scoped>
@use '../styles/search-bar.scss' as *;
:deep(.el-date-editor) {
  width: 128px;
}

.search-bar-item {
  height: 32px !important;
  .el-input__wrapper {
    height: 32px;
  }
  .el-input__inner {
    height: 32px;
  }
}
</style>
